#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>

#include "socket.h"

/* Description: Initial socket work context structure. */
int socket_init(socket_t *sock, char *hostname, int port)
{
	if( !sock || port<=0 )
	{
        return -1;
	}

    memset( sock, 0, sizeof(*sock) );
	sock->fd = -1;
	strncpy(sock->host, hostname, HOSTNAME_LEN);
	sock->port = port;

	return 0;
}

/* Description: Connect to socket server if not connected */
int socket_connect(socket_t *sock)
{
	int		   				rv = -1;
	int						n = 0;
	const   char			*dst;
	struct  sockaddr_in  	servaddr;
	struct 	hostent			*gethost = NULL;
	char            		ip[50];
	const   char   			*servip = NULL;
	struct  in_addr         **addr_list;
	int						i;

	// Check whether the hostname is a domain name or an IP address.
    if (inet_aton(sock->host, &servaddr.sin_addr) == 0)
    {
        // hostname is a dimain name, it needs to be resolved to an IP address.
        gethost = gethostbyname(sock->host);
        if (gethost == NULL)
        {
            printf("gethostbyname error: %s\n", strerror(errno));
            return -1;
        }
        addr_list = (struct in_addr **) gethost->h_addr_list;
        for (i = 0; addr_list[i] != NULL; i++)
        {
            memset(&servaddr, 0, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(sock->port);
            servaddr.sin_addr = *addr_list[i];

            sock->fd = socket(AF_INET, SOCK_STREAM, 0);
            if (sock->fd < 0)
            {
                printf("Create socket Failure:%s\n", strerror(errno));
                return -1;
            }

            rv = connect(sock->fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
            if (rv < 0)
            {
                //printf("Connect to server[%s:%d] failure:%s\n", inet_ntoa(*addr_list[i]), sock->port, strerror(errno));
                close(sock->fd);
                sock->fd = -1; // Connect Failure 
            }
            else
            {
                printf("Connect to server[%s:%d] successfully!\n", inet_ntoa(*addr_list[i]), sock->port);
                break;
            }
        }
    }
    else
    {
        // hostname is an IP address, use it directly.
        servip = sock->host;
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(sock->port);
        inet_aton(servip, &servaddr.sin_addr);

        sock->fd = socket(AF_INET, SOCK_STREAM, 0);
        if (sock->fd < 0)
        {
            printf("Create socket Failure:%s\n", strerror(errno));
            return -1;
        }

        rv = connect(sock->fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
        if (rv < 0)
        {
            //printf("Connect to server[%s:%d] failure:%s\n", servip, sock->port, strerror(errno));
            close(sock->fd);
            sock->fd = -1;
        }
        else
        {
            printf("Connect to server [%s:%d] successfully!\n", servip, sock->port);
        }
    }

    return sock->fd;
}
	
/* Description: Check and set socket connect status */
int check_connect(int sockfd)
{
	struct 			tcp_info info;
	int 			len=sizeof(info);

	if( sockfd < 0 )
	{
        return -1;
	}

	getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
	if((info.tcpi_state==TCP_ESTABLISHED))  // 则说明未断开  else 则说明断开了
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

/* Description: Close the socket */
int socket_close(socket_t *sock)
{
	if( !sock )
        return -1;

    if( sock->fd > 0)
    {
        close(sock->fd);
        sock->fd = -1;
    }

    return 0;
}
